/**
 @file ctc_asw_l2.c

 @date 2020-06-15

 @version v1.0


*/

/****************************************************************************
*
* Header Files
*
****************************************************************************/
#include "ctc_asw_common.h"
#include "ctc_l2.h"
#include "ctc_asw_l2.h"
#include "asw/include/drv_api.h"
#include "ctc_asw_interrupt.h"
#include "ctc_acl.h"
#include "ctc_asw_acl.h"
#include "ctc_port.h"
#include "ctc_asw_chip.h"

#define CTC_ASW_L2_MAX_LAG_COUNT 5
#define  CTC_ASW_L2_MCAST_ENTRY_MAX  512

/****************************************************************************
*
* Function
*
*****************************************************************************/
extern int32
_ctc_asw_acl_add_entry(uint8 lchip, uint32 group_id, ctc_acl_entry_t* acl_entry);
extern int32
_ctc_asw_acl_add_key_field_list(uint8 lchip, uint32 entry_id, ctc_field_key_t* p_field_list, uint32* p_field_cnt);
extern int32
_ctc_asw_acl_add_remove_valid(uint8 lchip, uint32 entry_id, uint8 is_add);
extern int32
_ctc_asw_acl_install_entry(uint8 lchip, uint32 entry_id);
extern int32
_ctc_asw_acl_check_action_field(uint8 lchip, ctc_acl_field_action_t* p_field_list, uint32* p_field_cnt);
extern int32
_ctc_asw_acl_build_action_field_list(uint8 lchip, uint32 entry_id, ctc_acl_field_action_t* p_field_list, uint32* p_field_cnt, uint8 is_add);

int32 
_ctc_asw_l2_flush_acl(uint8 lchip, ctc_l2_flush_fdb_t* pFlush)
{
    int32 entry_id = CTC_ASW_L2_ACL_ENTRY_MAX;
    ds_t tmp_key = {0};
    ds_t tmp_mask = {0};
    mask_tbl_entry_t tcam_entry;
    hw_mac_addr_t   acl_hw_mac = {0};
    uint16 acl_fid = 0;
    uint32  cmd  = 0;
    int32   ret = 0;
    hw_mac_addr_t   hw_mac = {0};

    tcam_entry.data_entry = (uint32 *)&tmp_key;
    tcam_entry.mask_entry = (uint32 *)&tmp_mask;
    
    for (entry_id = CTC_ASW_L2_ACL_ENTRY_MAX; entry_id >= 0; entry_id--)
    {
        if(!_ctc_asw_chip_check_acl_entry_id(lchip, entry_id))
        {
            continue;
        }

        cmd = DRV_IOR(Key160MacView0_t, DRV_ENTRY_FLAG);
        ret = ret ? ret : DRV_MASK_IOCTL(lchip, entry_id, cmd, &tcam_entry);
        acl_fid = GetKey160MacView0(V, stag_f, tmp_key);
        GetKey160MacView0(A, da_f, tmp_key, acl_hw_mac);
        FDB_SET_HW_MAC(hw_mac, pFlush->mac);
        if (( pFlush->flush_type == CTC_L2_FDB_ENTRY_OP_BY_MAC && sal_memcmp(hw_mac, acl_hw_mac, 6) == 0) ||
            (((pFlush->flush_type == CTC_L2_FDB_ENTRY_OP_BY_VID)||(pFlush->flush_type == CTC_L2_FDB_ENTRY_OP_BY_PORT_VLAN)) && (acl_fid == pFlush->fid)) ||
            (pFlush->flush_type == CTC_L2_FDB_ENTRY_OP_ALL))
        {
            ret = ret ? ret : _ctc_asw_acl_add_remove_valid(lchip, entry_id, 0);
            ret = ret ? ret : _ctc_asw_chip_set_acl_entry_id(lchip, entry_id, FALSE);
        }
    }
    
    return ret;
}

#define ______API______
/**
 @brief    add a fdb entry

 @param[in] l2_addr maintain the data from the ctc layer

 @return CTC_E_XXX

 @remarks To Add l2 fdb entry.

*/
int32
ctc_asw_l2_add_fdb(uint8 lchip, ctc_l2_addr_t* l2_addr)
{
    uint32          cmd  = 0;
    uint32          value  = 0;
    uint32          value_tmp  = 0;
    uint32          limit_num  = 0;
    uint32          learn_count  = 0;
    int32           ret = 0;
    hw_mac_addr_t   hw_mac = {0};
    ArlTable_m     fdb_key;
    PortxLearnLimit_m     portx_learn_limit;
    PortxLearnStat_m      portx_learn_stat;

    CTC_PTR_VALID_CHECK(l2_addr);
    CTC_ASW_FID_RANGE_CHECK(l2_addr->fid);
    CTC_MAX_GPORT_CHECK(l2_addr->gport);

    CTC_L2_MAC_IS_UCAST(l2_addr->mac[0]);

    sal_memset(&fdb_key, 0, sizeof(ArlTable_m));
    sal_memset(&portx_learn_limit, 0, sizeof(PortxLearnLimit_m));
    value = CTC_IS_LINKAGG_PORT(l2_addr->gport)?CTC_ASW_LAG_BASE + CTC_GPORT_LINKAGG_ID(l2_addr->gport):l2_addr->gport;
    value_tmp = CTC_IS_LINKAGG_PORT(l2_addr->gport)?CTC_ASW_MAX_PORT_NUM_PER_CHIP + CTC_GPORT_LINKAGG_ID(l2_addr->gport):l2_addr->gport;

    CTC_API_LOCK(lchip);
    if (!CTC_FLAG_ISSET(l2_addr->flag,CTC_L2_FLAG_IS_STATIC))
    {
        cmd = DRV_IOR(PortxLearnLimit_t,DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip,value_tmp,cmd,&portx_learn_limit);
        limit_num = GetPortxLearnLimit(V,learningLimit_f,&portx_learn_limit);
        cmd = DRV_IOR(PortxLearnStat_t,DRV_ENTRY_FLAG);
        ret = ret ? ret : DRV_IOCTL(lchip,value_tmp,cmd,&portx_learn_stat);
        learn_count = GetPortxLearnStat(V,learningCounter_f,&portx_learn_stat);
        if ((learn_count >= limit_num) && (0 != limit_num))
        {
            CTC_API_UNLOCK(lchip);
            return CTC_E_NO_RESOURCE;
        }
    }
    FDB_SET_HW_MAC(hw_mac, l2_addr->mac);
    SetArlTable(A,macAddr_f,&fdb_key,hw_mac);
    SetArlTable(V,fid_f,&fdb_key,l2_addr->fid);
    SetArlTable(V,arlType_f,&fdb_key,0);
    SetArlTable(V,portId_f,&fdb_key,value);
    SetArlTable(V,state_f,&fdb_key,CTC_FLAG_ISSET(l2_addr->flag,CTC_L2_FLAG_IS_STATIC)?1:5);
    SetArlTable(V,dmacFilter_f,&fdb_key,0);
    if (CTC_FLAG_ISSET(l2_addr->flag,CTC_L2_FLAG_DISCARD))
    {
        SetArlTable(V,dmacFilter_f,&fdb_key,1);
    }
    SetArlTable(V,smacFilter_f,&fdb_key,0);
    if (CTC_FLAG_ISSET(l2_addr->flag,CTC_L2_FLAG_SRC_DISCARD))
    {
        SetArlTable(V,smacFilter_f,&fdb_key,1);
    }

    SetArlTable(V,stationMoved_f,&fdb_key,0);
    SetArlTable(V,pendingLearn_f,&fdb_key,0);
    SetArlTable(V,mstp_f,&fdb_key,0);
    cmd = DRV_IOHA(ArlTable_t,DRV_ENTRY_FLAG);
    ret = ret ? ret : DRV_IOCTL(lchip,0,cmd,&fdb_key);
    CTC_API_UNLOCK(lchip);

    return ret;
}

/**
 @brief Delete a fdb entry

 @maintain the data from the ctc layer

 @return CTC_E_XXX

*/
int32
ctc_asw_l2_remove_fdb(uint8 lchip, ctc_l2_addr_t* l2_addr)
{
    ArlTable_m     fdb_key;
    uint32          cmd  = 0;
    uint32          ret  = 0;
    hw_mac_addr_t   hw_mac = {0};

    CTC_PTR_VALID_CHECK(l2_addr);
    CTC_ASW_FID_RANGE_CHECK(l2_addr->fid);
    CTC_L2_MAC_IS_UCAST(l2_addr->mac[0]);

    sal_memset(&fdb_key, 0, sizeof(ArlTable_m));

    CTC_API_LOCK(lchip);
    FDB_SET_HW_MAC(hw_mac, l2_addr->mac);
    SetArlTable(A,macAddr_f,&fdb_key,hw_mac);
    SetArlTable(V,fid_f,&fdb_key,l2_addr->fid);
    SetArlTable(V,arlType_f,&fdb_key,0);
    cmd = DRV_IOHL(ArlTable_t,DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip,0,cmd,&fdb_key);
    SetArlTable(V,state_f,&fdb_key,0);
    cmd = DRV_IOHR(ArlTable_t,DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip,0,cmd,&fdb_key);
    CTC_API_UNLOCK(lchip);

    return ret;
}

int32
ctc_asw_l2mcast_add_addr(uint8 lchip, ctc_l2_mcast_addr_t* l2mc_addr)
{
    McTable_m      mc_fdb_key;
    uint32          cmd = 0;
    int32           ret = 0;
    hw_mac_addr_t   hw_mac = {0};
    ctc_acl_property_t prop;
    CTC_PTR_VALID_CHECK(l2mc_addr);
    CTC_ASW_FID_RANGE_CHECK(l2mc_addr->fid);
    CTC_L2_MAC_IS_MCAST(l2mc_addr->mac[0]);

    sal_memset(&mc_fdb_key, 0, sizeof(McTable_m));
    CTC_API_LOCK(lchip);
    if (!(CTC_FLAG_ISSET(l2mc_addr->flag, CTC_L2_FLAG_SYSTEM_RSV)))
    {
        FDB_SET_HW_MAC(hw_mac, l2mc_addr->mac);
        SetMcTable(A, macAddr_f, &mc_fdb_key, hw_mac);
        SetMcTable(V, fid_f, &mc_fdb_key, l2mc_addr->fid);
        SetMcTable(V, arlType_f, &mc_fdb_key, 0);
        SetMcTable(V, portId_f, &mc_fdb_key, 0);
        SetMcTable(V, state_f, &mc_fdb_key, 1);
        SetMcTable(V, dmacFilter_f, &mc_fdb_key, 0);
        SetMcTable(V, smacFilter_f, &mc_fdb_key, 0);
        if (CTC_FLAG_ISSET(l2mc_addr->flag, CTC_L2_FLAG_SRC_DISCARD))
        {
            SetMcTable(V, smacFilter_f, &mc_fdb_key, 1);
        }

        SetMcTable(V, stationMoved_f, &mc_fdb_key, 0);
        SetMcTable(V, pendingLearn_f, &mc_fdb_key, 0);
        SetMcTable(V, mstp_f, &mc_fdb_key, 0);
        cmd = DRV_IOHA(McTable_t, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, 0, cmd, &mc_fdb_key);
    }
    else
    {
        ctc_acl_entry_t acl_entry;
        uint32 p_field_cnt = 2;
        ctc_field_key_t key_field[2];
        ctc_field_key_t* p_field_list = &key_field[0];
        mac_addr_t  mac_da_addr_mask = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
        uint32 entry_id = 0;
        
        sal_memset(&acl_entry,0,sizeof(ctc_acl_entry_t));
        sal_memset(&prop,0,sizeof(ctc_acl_property_t));
        sal_memset(key_field, 0, sizeof(ctc_field_key_t));
        CTC_ERROR_GOTO(_ctc_asw_chip_get_acl_entry_id(lchip, &entry_id),ret,error_pro);

        acl_entry.entry_id = entry_id;
        acl_entry.key_type = CTC_ACL_KEY_MAC;
        CTC_ERROR_GOTO(_ctc_asw_acl_add_entry(lchip, 0, &acl_entry),ret,error_pro);

        key_field[0].type = CTC_FIELD_KEY_MAC_DA;
        key_field[0].ext_data = l2mc_addr->mac; 
        key_field[0].ext_mask = mac_da_addr_mask;
        
        key_field[1].type = CTC_FIELD_KEY_SVLAN_ID;
        key_field[1].data = l2mc_addr->fid;
        key_field[1].mask = 0xffff;
        CTC_ERROR_GOTO(_ctc_asw_acl_add_key_field_list(lchip, acl_entry.entry_id, p_field_list, &p_field_cnt),ret,error_pro);
        CTC_ERROR_GOTO( _ctc_asw_acl_install_entry(lchip, entry_id),ret,error_pro);
        ret = _ctc_asw_chip_set_acl_entry_id(lchip, entry_id, TRUE);
    }
error_pro:
    CTC_API_UNLOCK(lchip);
    return ret;
}

/**
 @brief Remove an entry in the multicast table

 @L2 multicast address

 @return CTC_E_XXX

*/
int32
ctc_asw_l2mcast_remove_addr(uint8 lchip, ctc_l2_mcast_addr_t* l2mc_addr)
{
    McTable_m      mc_fdb_key;
    uint32          cmd = 0;
    int32           ret = 0;
    hw_mac_addr_t   hw_mac = {0};
    CTC_PTR_VALID_CHECK(l2mc_addr);
    CTC_ASW_FID_RANGE_CHECK(l2mc_addr->fid);
    CTC_L2_MAC_IS_MCAST(l2mc_addr->mac[0]);

    sal_memset(&mc_fdb_key, 0, sizeof(McTable_m));
    CTC_API_LOCK(lchip);
    FDB_SET_HW_MAC(hw_mac, l2mc_addr->mac);
    SetMcTable(A,macAddr_f,&mc_fdb_key,hw_mac);
    SetMcTable(V,fid_f,&mc_fdb_key,l2mc_addr->fid);
    SetMcTable(V,arlType_f,&mc_fdb_key,0);
    cmd = DRV_IOHL(McTable_t,DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip,0,cmd,&mc_fdb_key);
    SetMcTable(V,state_f,&mc_fdb_key,0);

    cmd = DRV_IOHR(McTable_t,DRV_ENTRY_FLAG);
    ret = ret ? ret : DRV_IOCTL(lchip,0,cmd,&mc_fdb_key);

    if (ret == DRV_E_NOT_EXIST)
    {
        uint32 entry_id = 0;

        ret = 0;
        CTC_ERROR_GOTO(_ctc_asw_chip_find_entry(lchip, hw_mac, l2mc_addr->fid,&entry_id),ret,error_pro);
        CTC_ERROR_GOTO(_ctc_asw_acl_add_remove_valid(lchip, entry_id, 0),ret,error_pro);
        ret =_ctc_asw_chip_set_acl_entry_id(lchip, entry_id, FALSE);
    }
error_pro:
    CTC_API_UNLOCK(lchip);
    return ret;
}

int32
ctc_asw_l2mcast_add_member(uint8 lchip, ctc_l2_mcast_addr_t* l2mc_addr)
{
    McTable_m            mc_fdb_key;
    L2mcMappingTable_m  mc_mapping_table;
    uint32          cmd = 0;
    uint32          l2mc_index  = 0;
    int32           ret = 0;
    hw_mac_addr_t   hw_mac = {0};
    uint8           linkagg_id = 0;

    CTC_PTR_VALID_CHECK(l2mc_addr);
    CTC_ASW_FID_RANGE_CHECK(l2mc_addr->fid);
    CTC_L2_MAC_IS_MCAST(l2mc_addr->mac[0]);

    sal_memset(&mc_fdb_key, 0, sizeof(McTable_m));
    sal_memset(&mc_mapping_table, 0, sizeof(L2mcMappingTable_m));

    CTC_API_LOCK(lchip);
    FDB_SET_HW_MAC(hw_mac, l2mc_addr->mac);
    SetMcTable(A,macAddr_f,&mc_fdb_key,hw_mac);
    SetMcTable(V,fid_f,&mc_fdb_key,l2mc_addr->fid);
    SetMcTable(V,arlType_f,&mc_fdb_key,0);
    cmd = DRV_IOHL(McTable_t,DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip,0,cmd,&mc_fdb_key);
    l2mc_index = GetMcTable(V,portId_f,&mc_fdb_key);
    /*mirror en set mirror en */
    SetL2mcMappingTable(V,bypassEvt_f,&mc_mapping_table,1);
    SetL2mcMappingTable(V,bypassStp_f,&mc_mapping_table,0);
    linkagg_id = (((l2mc_addr->member.port_bmp[1] & 0x3) << 3) | ((l2mc_addr->member.port_bmp[0] >> CTC_ASW_MAX_PORT_NUM_PER_CHIP) & 0x7));
    SetL2mcMappingTable(V,lagBitmap_f,&mc_mapping_table,linkagg_id);
    l2mc_addr->member.port_bmp[0] = (l2mc_addr->member.port_bmp[0] & 0xFFFFFFF);
    SetL2mcMappingTable(V,dstBitmap_f,&mc_mapping_table,l2mc_addr->member.port_bmp[0]);
    cmd = DRV_IOW(L2mcMappingTable_t,DRV_ENTRY_FLAG);
    ret = ret ? ret : DRV_IOCTL(lchip,l2mc_index,cmd,&mc_mapping_table);
    
    if (ret == DRV_E_NOT_EXIST)
    {
        uint32 entry_id = 0;
        ctc_acl_field_action_t act_field;
        uint32 cnt = 1;

        ret = 0;
        sal_memset(&act_field, 0, sizeof(ctc_acl_field_action_t));
        ret = _ctc_asw_chip_find_entry(lchip, hw_mac, l2mc_addr->fid,&entry_id);

        act_field.type = CTC_ACL_FIELD_ACTION_REDIRECT_PORT;
        act_field.data0 = l2mc_addr->member.port_bmp[0];
        act_field.data1 = linkagg_id;

        ret = ret? ret : _ctc_asw_acl_build_action_field_list(lchip, entry_id, &act_field, &cnt, 1);
    }
    CTC_API_UNLOCK(lchip);
    return ret;
}

int32
ctc_asw_l2mcast_remove_member(uint8 lchip, ctc_l2_mcast_addr_t* l2mc_addr)
{
    McTable_m            mc_fdb_key;
    L2mcMappingTable_m  mc_mapping_table;
    uint32          cmd  = 0;
    uint32          l2mc_index  = 0;
    uint32          value  = 0;
    int32           ret = 0;
    hw_mac_addr_t   hw_mac = {0};
    uint8           linkagg_id = 0;

    CTC_PTR_VALID_CHECK(l2mc_addr);
    CTC_ASW_FID_RANGE_CHECK(l2mc_addr->fid);
    CTC_L2_MAC_IS_MCAST(l2mc_addr->mac[0]);

    sal_memset(&mc_fdb_key, 0, sizeof(McTable_m));
    sal_memset(&mc_mapping_table, 0, sizeof(L2mcMappingTable_m));

    CTC_API_LOCK(lchip);
    FDB_SET_HW_MAC(hw_mac, l2mc_addr->mac);
    SetMcTable(A,macAddr_f,&mc_fdb_key,hw_mac);
    SetMcTable(V,fid_f,&mc_fdb_key,l2mc_addr->fid);
    SetMcTable(V,arlType_f,&mc_fdb_key,0);
    cmd = DRV_IOHL(McTable_t,DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip,0,cmd,&mc_fdb_key);
    l2mc_index = GetMcTable(V,portId_f,&mc_fdb_key);
    cmd = DRV_IOR(L2mcMappingTable_t,DRV_ENTRY_FLAG);
    ret = ret ? ret : DRV_IOCTL(lchip,l2mc_index,cmd,&mc_mapping_table);

    linkagg_id = GetL2mcMappingTable(V,lagBitmap_f,&mc_mapping_table);
    linkagg_id = ~(((l2mc_addr->member.port_bmp[1] & 0x3) << 3) |((l2mc_addr->member.port_bmp[0] >> CTC_ASW_MAX_PORT_NUM_PER_CHIP) & 0x7)) & linkagg_id;
    SetL2mcMappingTable(V,lagBitmap_f,&mc_mapping_table,linkagg_id);
    value = GetL2mcMappingTable(V,dstBitmap_f,&mc_mapping_table);
    value = (~(l2mc_addr->member.port_bmp[0] & 0xFFFFFFF) & value);
    SetL2mcMappingTable(V,dstBitmap_f,&mc_mapping_table,value);
    cmd = DRV_IOW(L2mcMappingTable_t,DRV_ENTRY_FLAG);
    ret = ret ? ret : DRV_IOCTL(lchip,l2mc_index,cmd,&mc_mapping_table);

    if (ret == DRV_E_NOT_EXIST)
    {
        uint32 entry_id = 0;
        uint32 cnt = 1;
        ctc_acl_field_action_t act_field;
        
        AclBaseAction_m action;
        ret = 0;
        sal_memset(&act_field, 0, sizeof(ctc_acl_field_action_t));
        ret = _ctc_asw_chip_find_entry(lchip, hw_mac, l2mc_addr->fid,&entry_id);

        cmd = DRV_IOR(AclBaseAction_t, DRV_ENTRY_FLAG);
        ret = ret? ret : DRV_IOCTL(lchip, entry_id, cmd, &action);
        linkagg_id = GetAclBaseAction(V,redirectLagBitmap_f,&action);
        linkagg_id = ~(((l2mc_addr->member.port_bmp[1] & 0x3) << 3) |((l2mc_addr->member.port_bmp[0] >> CTC_ASW_MAX_PORT_NUM_PER_CHIP) & 0x7)) & linkagg_id;
        value = GetAclBaseAction(V,redirectPortBitmap_f,&action);
        value = (~(l2mc_addr->member.port_bmp[0] & 0xFFFFFFF) & value);
        
        act_field.type = CTC_ACL_FIELD_ACTION_REDIRECT_PORT;
        act_field.data0 = value;
        act_field.data1 = linkagg_id;
        ret = ret? ret : _ctc_asw_acl_build_action_field_list(lchip, entry_id, &act_field, &cnt, 1);
    }
    CTC_API_UNLOCK(lchip);
    return ret;
}

int32
ctc_asw_l2_flush_fdb(uint8 lchip, ctc_l2_flush_fdb_t* pFlush)
{
    PortFastAgingCfg_m  port_fast_aging;
    FidFastAgingCfg_m   fid_fast_aging;
    MacFastAgingCfg_m   mac_fast_aging;
    FastAgingStatus_m    fast_aging_status;
    hw_mac_addr_t   hw_mac = {0};
    uint32  cmd  = 0;
    uint32  port_bitmap[2]  = {0};
    uint32  done  = 0;
    uint32  value  = 0;
    int32   ret = 0;

    CTC_PTR_VALID_CHECK(pFlush);
    CTC_ASW_FID_RANGE_CHECK(pFlush->fid);
    CTC_MAX_GPORT_CHECK(pFlush->gport);

    CTC_API_LOCK(lchip);
    cmd = DRV_IOR(FastAgingStatus_t,DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip,0,cmd,&fast_aging_status);
    done = GetFastAgingStatus(V,done_f,&fast_aging_status);
    if (done != 1)
    {
        CTC_API_UNLOCK(lchip);
        return CTC_E_HW_BUSY;
    }

    if (pFlush->flush_type == CTC_L2_FDB_ENTRY_OP_BY_PORT )
    {
        value = CTC_IS_LINKAGG_PORT(pFlush->gport)?CTC_ASW_LAG_BASE + CTC_GPORT_LINKAGG_ID(pFlush->gport):pFlush->gport;
        cmd = DRV_IOR(PortFastAgingCfg_t, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip,0,cmd,&port_fast_aging);
        SetPortFastAgingCfg(V,glbFastAging_f,&port_fast_aging,0);
        SetPortFastAgingCfg(V,portId_f,&port_fast_aging,value);
        SetPortFastAgingCfg(V,enable_f,&port_fast_aging,1);
        SetPortFastAgingCfg(V,staticEntry_f,&port_fast_aging,(pFlush->flush_flag == CTC_L2_FDB_ENTRY_DYNAMIC)?0:1);
        cmd = DRV_IOW(PortFastAgingCfg_t,DRV_ENTRY_FLAG);
        ret = ret ? ret : DRV_IOCTL(lchip,0,cmd,&port_fast_aging);
        SetPortFastAgingCfg(V,enable_f,&port_fast_aging,0);
        cmd = DRV_IOW(PortFastAgingCfg_t,DRV_ENTRY_FLAG);
        ret = ret ? ret : DRV_IOCTL(lchip,0,cmd,&port_fast_aging);
    }
    else if (pFlush->flush_type == CTC_L2_FDB_ENTRY_OP_ALL)
    {
        cmd = DRV_IOR(PortFastAgingCfg_t,DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip,0,cmd,&port_fast_aging);
        SetPortFastAgingCfg(V,enable_f,&port_fast_aging,1);
        SetPortFastAgingCfg(V,glbFastAging_f,&port_fast_aging,1);
        SetPortFastAgingCfg(V,staticEntry_f,&port_fast_aging,(pFlush->flush_flag == CTC_L2_FDB_ENTRY_DYNAMIC)?0:1);
        cmd = DRV_IOW(PortFastAgingCfg_t,DRV_ENTRY_FLAG);
        ret = ret ? ret : DRV_IOCTL(lchip,0,cmd,&port_fast_aging);
        SetPortFastAgingCfg(V,enable_f,&port_fast_aging,0);
        cmd = DRV_IOW(PortFastAgingCfg_t,DRV_ENTRY_FLAG);
        ret = ret ? ret : DRV_IOCTL(lchip,0,cmd,&port_fast_aging);
    }
    else if  ((pFlush->flush_type == CTC_L2_FDB_ENTRY_OP_BY_VID)||(pFlush->flush_type == CTC_L2_FDB_ENTRY_OP_BY_PORT_VLAN))
    {
        value = CTC_IS_LINKAGG_PORT(pFlush->gport)?CTC_ASW_MAX_PORT_NUM_PER_CHIP + CTC_GPORT_LINKAGG_ID(pFlush->gport):pFlush->gport;
        cmd = DRV_IOR(FidFastAgingCfg_t,DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip,0,cmd,&fid_fast_aging);
        SetFidFastAgingCfg(V,enable_f,&fid_fast_aging,1);
        SetFidFastAgingCfg(V,fid_f,&fid_fast_aging,pFlush->fid);
        if (pFlush->flush_type == CTC_L2_FDB_ENTRY_OP_BY_PORT_VLAN)
        {
            CTC_BMP_SET(port_bitmap,value);
        }
        else
        {
            port_bitmap[0] = 0xFFFFFFFF;
            port_bitmap[1] = 0x3;
        }
        SetFidFastAgingCfg(A,portBitmap_f,&fid_fast_aging,port_bitmap);
        SetFidFastAgingCfg(V,staticEntry_f,&fid_fast_aging,(pFlush->flush_flag == CTC_L2_FDB_ENTRY_DYNAMIC)?0:1);
        cmd = DRV_IOW(FidFastAgingCfg_t,DRV_ENTRY_FLAG);
        ret = ret ? ret : DRV_IOCTL(lchip,0,cmd,&fid_fast_aging);
        SetFidFastAgingCfg(V,enable_f,&fid_fast_aging,0);
        cmd = DRV_IOW(FidFastAgingCfg_t,DRV_ENTRY_FLAG);
        ret = ret ? ret : DRV_IOCTL(lchip,0,cmd,&fid_fast_aging);
    }
    else if (pFlush->flush_type == CTC_L2_FDB_ENTRY_OP_BY_MAC)
    {
        cmd = DRV_IOR(MacFastAgingCfg_t,DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip,0,cmd,&mac_fast_aging);
        FDB_SET_HW_MAC(hw_mac, pFlush->mac);
        SetMacFastAgingCfg(A,mac_f,&mac_fast_aging,hw_mac);
        SetMacFastAgingCfg(V,enable_f,&mac_fast_aging,1);
        /* SetMacFastAgingCfg(V,ipmcFlag_f,&mac_fast_aging,0);*/
        SetMacFastAgingCfg(V,staticEntry_f,&mac_fast_aging,(pFlush->flush_flag == CTC_L2_FDB_ENTRY_DYNAMIC)?0:1);
        port_bitmap[0] = 0xFFFFFFFF;
        port_bitmap[1] = 0x3;
        SetMacFastAgingCfg(A,portBitmap_f,&mac_fast_aging,port_bitmap);
        cmd = DRV_IOW(MacFastAgingCfg_t,DRV_ENTRY_FLAG);
        ret = ret ? ret : DRV_IOCTL(lchip,0,cmd,&mac_fast_aging);
        SetMacFastAgingCfg(V,enable_f,&mac_fast_aging,0);
        cmd = DRV_IOW(MacFastAgingCfg_t,DRV_ENTRY_FLAG);
        ret = ret ? ret : DRV_IOCTL(lchip,0,cmd,&mac_fast_aging);
    }
    if(((pFlush->flush_type == CTC_L2_FDB_ENTRY_OP_BY_MAC) || (pFlush->flush_type == CTC_L2_FDB_ENTRY_OP_ALL) || 
        ((pFlush->flush_type == CTC_L2_FDB_ENTRY_OP_BY_VID)||(pFlush->flush_type == CTC_L2_FDB_ENTRY_OP_BY_PORT_VLAN)))
        && (pFlush->flush_flag != CTC_L2_FDB_ENTRY_DYNAMIC))
    {
        ret = _ctc_asw_l2_flush_acl(lchip, pFlush);
    }
    CTC_API_UNLOCK(lchip);
    return ret;
}

int32
ctc_asw_l2_get_fdb_count(uint8 lchip, ctc_l2_fdb_query_t* pq)
{
    int32     ret = 0;
    uint32    cmd = 0;
    uint32    i = 0;
    uint32    value  = 0;
    PortxLearnStat_m portx_learn_stat;

    CTC_PTR_VALID_CHECK(pq);
    CTC_ASW_FID_RANGE_CHECK(pq->fid);
    CTC_MAX_GPORT_CHECK(pq->gport);
    value = CTC_IS_LINKAGG_PORT(pq->gport)?CTC_ASW_MAX_PORT_NUM_PER_CHIP + CTC_GPORT_LINKAGG_ID(pq->gport):pq->gport;
    pq->count = 0;

    CTC_API_LOCK(lchip);
    if (pq->query_type == CTC_L2_FDB_ENTRY_OP_BY_PORT)
    {
        cmd = DRV_IOR(PortxLearnStat_t,DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip,value,cmd,&portx_learn_stat);
        pq->count = GetPortxLearnStat(V,learningCounter_f,&portx_learn_stat);
    }
    else if(pq->query_type == CTC_L2_FDB_ENTRY_OP_ALL)
    {
        for (i = 0; i < (CTC_ASW_MAX_PORT_NUM_PER_CHIP + CTC_ASW_L2_MAX_LAG_COUNT); i++)
        {
            cmd = DRV_IOR(PortxLearnStat_t,DRV_ENTRY_FLAG);
            ret = DRV_IOCTL(lchip,i,cmd,&portx_learn_stat);
            pq->count += GetPortxLearnStat(V,learningCounter_f,&portx_learn_stat);
        }
    }
    CTC_API_UNLOCK(lchip);

    return ret;
}

int32
ctc_asw_l2_get_fdb_entry(uint8 lchip,ctc_l2_fdb_query_t* pQuery,ctc_l2_fdb_query_rst_t* query_rst)
{
    hdump_entry_t   data;
    uint32          cmd  = 0;
    ArlTable_m*     fdb_key = NULL;
    McTable_m*      mc_fdb_key = NULL;
    uint32          i = 0;
    int32           ret = 0;
    hw_mac_addr_t   hw_mac = {0};
    uint32          flag;
    CTC_PTR_VALID_CHECK(pQuery);
    CTC_PTR_VALID_CHECK(query_rst);

    sal_memset(&data, 0, sizeof(hdump_entry_t));
    if (CTC_L2_FDB_ENTRY_MCAST == pQuery->query_flag)
    {
        mc_fdb_key = sal_malloc(sizeof(McTable_m)*(query_rst->buffer_len/sizeof(ctc_l2_addr_t)));
        if (mc_fdb_key)
        {
            sal_memset(mc_fdb_key, 0, sizeof(McTable_m)*(query_rst->buffer_len / sizeof(ctc_l2_addr_t)));
        }
    }
    else
    {
        fdb_key = sal_malloc(sizeof(ArlTable_m)*(query_rst->buffer_len/sizeof(ctc_l2_addr_t)));
        if (fdb_key)
        {
            sal_memset(fdb_key, 0, sizeof(ArlTable_m)*(query_rst->buffer_len / sizeof(ctc_l2_addr_t)));
        }
    }
    
    if ((NULL == fdb_key) && (NULL == mc_fdb_key))
    {
        ret = CTC_E_NO_MEMORY;
        goto roll_back_0;
    }
    CTC_API_LOCK(lchip);
    /*need entry_num index and count for l2 fdb or acl quary*/
    if (CTC_L2_FDB_ENTRY_OP_BY_MAC_VLAN == pQuery->query_type && CTC_L2_FDB_ENTRY_MCAST != pQuery->query_flag)
    {
        FDB_SET_HW_MAC(hw_mac, pQuery->mac);
        SetArlTable(A, macAddr_f, fdb_key, hw_mac);
        SetArlTable(V, fid_f, fdb_key, pQuery->fid);
        SetArlTable(V, arlType_f, fdb_key, 0);
        cmd = DRV_IOHL(ArlTable_t, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, 0, cmd, fdb_key);
        if (!ret)
        {
            GetArlTable(A, macAddr_f, fdb_key, hw_mac);
            CTC_ASW_SET_USER_MAC(query_rst->buffer[0].mac, hw_mac);
            query_rst->buffer[0].fid = GetArlTable(V, fid_f, fdb_key);
            query_rst->buffer[0].gport = GetArlTable(V, portId_f, fdb_key);
            flag = GetArlTable(V, state_f, fdb_key);
            query_rst->buffer[i].flag = (flag == CTC_L2_FLAG_IS_STATIC) ? 1 : 0;
            pQuery->count = 1;
        }
        else if (DRV_E_NOT_EXIST == ret)
        {
            ret = 0;
            pQuery->count = 0;
        }
        query_rst->is_end = 1;
    }
    else if(CTC_L2_FDB_ENTRY_OP_ALL == pQuery->query_type)
    {
        data.entry_num = query_rst->buffer_len / sizeof(ctc_l2_addr_t);
        if (!(query_rst->start_index >= CTC_ASW_L2_MCAST_ENTRY_MAX && CTC_L2_FDB_ENTRY_MCAST == pQuery->query_flag))
        {
            data.data_entry = (CTC_L2_FDB_ENTRY_MCAST == pQuery->query_flag)? (uint32*)mc_fdb_key : (uint32*)fdb_key;
            data.start_index = query_rst->start_index;
            cmd = DRV_IOHD(((CTC_L2_FDB_ENTRY_MCAST == pQuery->query_flag)? McTable_t : ArlTable_t), DRV_ENTRY_FLAG);
            ret = DRV_IOCTL(lchip, 0, cmd, &data);
            pQuery->count = data.valid_num;
            query_rst->next_query_index = data.next_index;
            query_rst->is_end = (query_rst->next_query_index ? 0 : 1);
        }
        else
        {
            query_rst->next_query_index = query_rst->start_index;
            pQuery->count = 0;
        }
        /*quary in l2 fdb*/
        for (i = 0; i < data.valid_num ; i++)
        {
            if (CTC_L2_FDB_ENTRY_MCAST == pQuery->query_flag)
            {
                GetMcTable(A, macAddr_f, &mc_fdb_key[i], hw_mac);
                CTC_ASW_SET_USER_MAC(query_rst->buffer[i].mac, hw_mac);
                query_rst->buffer[i].fid = GetMcTable(V, fid_f, &mc_fdb_key[i]);
                query_rst->buffer[i].gport = GetMcTable(V, portId_f, &mc_fdb_key[i]);
                query_rst->buffer[i].flag = 1;
            }
            else
            {
                GetArlTable(A, macAddr_f, &fdb_key[i], hw_mac);
                CTC_ASW_SET_USER_MAC(query_rst->buffer[i].mac, hw_mac);
                query_rst->buffer[i].fid = GetArlTable(V, fid_f, &fdb_key[i]);
                if (GetArlTable(V, portId_f, &fdb_key[i]) > (CTC_ASW_MAX_PHY_PORT))
                {
                    query_rst->buffer[i].gport = 0x1F00 | (GetArlTable(V, portId_f, &fdb_key[i]) - CTC_ASW_LAG_BASE);
                }
                else
                {
                    query_rst->buffer[i].gport = GetArlTable(V, portId_f, &fdb_key[i]);
                }
                flag = GetArlTable(V, state_f, &fdb_key[i]);
                query_rst->buffer[i].flag = (flag == CTC_L2_FLAG_IS_STATIC) ? 1 : 0;
            }
        }

        /*if index >= 512，quary in acl*/
        if ((pQuery->count != data.entry_num) && CTC_L2_FDB_ENTRY_MCAST == pQuery->query_flag && (query_rst->is_end || (query_rst->next_query_index >= CTC_ASW_L2_MCAST_ENTRY_MAX)))
        {
            uint32 entry_id = 0;
            uint32 cmd = 0;
            ds_t tmp_key = {0};
            ds_t tmp_mask = {0};
            mask_tbl_entry_t tcam_entry;
            hw_mac_addr_t   acl_hw_mac = {0};

            query_rst->next_query_index = query_rst->is_end ?CTC_ASW_L2_MCAST_ENTRY_MAX:query_rst->next_query_index;
            query_rst->is_end = 0;
            tcam_entry.data_entry = (uint32 *)&tmp_key;
            tcam_entry.mask_entry = (uint32 *)&tmp_mask;
            for (entry_id = query_rst->next_query_index - CTC_ASW_L2_MCAST_ENTRY_MAX; entry_id <= CTC_ASW_L2_ACL_ENTRY_MAX; entry_id++)
            {
                query_rst->next_query_index ++;
                if(!_ctc_asw_chip_check_acl_entry_id(lchip, entry_id))
                {
                    continue;
                }
                cmd = DRV_IOR(Key160MacView0_t, DRV_ENTRY_FLAG);
                ret = ret ? ret : DRV_MASK_IOCTL(lchip, entry_id, cmd, &tcam_entry);
                
                GetKey160MacView0(A,da_f,tmp_key,acl_hw_mac);
                CTC_ASW_SET_USER_MAC(query_rst->buffer[i].mac,acl_hw_mac);

                query_rst->buffer[i].fid = GetKey160MacView0(V, stag_f, tmp_key);
                query_rst->buffer[i].gport = entry_id+CTC_ASW_L2_MCAST_ENTRY_MAX;
                query_rst->buffer[i].flag = 1;
                pQuery->count ++;
                if(pQuery->count == data.entry_num)
                {
                    entry_id++;
                    break;
                }
                i++;
            }
            if (entry_id == CTC_ASW_L2_ACL_ENTRY_MAX + 1)
            {
                query_rst->is_end = 1;
            }
        }
    }
roll_back_0:
    if (fdb_key)
    {
        sal_free(fdb_key);
    }
    if (mc_fdb_key)
    {
        sal_free(mc_fdb_key);
    }
    
    CTC_API_UNLOCK(lchip);
    return ret;

}

int32
ctc_asw_l2_set_fid_property(uint8 lchip, uint16 fid_id, ctc_l2_fid_property_t property, uint32 value)
{
    uint32 cmd = 0;
    int32  ret = 0;
    IvtProfile_m ivt_profile;
    uint32 ivt_pro_index = 0;

    CTC_ASW_FID_RANGE_CHECK(fid_id);
    ivt_pro_index = (fid_id < 128) ? fid_id : 0;

    CTC_API_LOCK(lchip);
    cmd = DRV_IOR(IvtProfile_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, ivt_pro_index, cmd, &ivt_profile);
    value  = (value) ? 1 : 0;
    switch (property)
    {
        case CTC_L2_FID_PROP_LEARNING:
            SetIvtProfile(V, fidCfgSa_f, &ivt_profile,value);
            break;
        case CTC_L2_FID_PROP_DROP_UNKNOWN_UCAST:
            SetIvtProfile(V, ulfDrop_f, &ivt_profile,value);
            break;
        case CTC_L2_FID_PROP_DROP_UNKNOWN_MCAST:
            SetIvtProfile(V, mlfDrop_f, &ivt_profile,value);
            break;
        case CTC_L2_FID_PROP_DROP_BCAST:
            SetIvtProfile(V, bcDrop_f, &ivt_profile,value);
            break;
        default:
            CTC_API_UNLOCK(lchip);
            return CTC_E_INVALID_PARAM;
    }
    cmd = DRV_IOW(IvtProfile_t, DRV_ENTRY_FLAG);
    ret = ret ? ret : (DRV_IOCTL(lchip, ivt_pro_index, cmd, &ivt_profile));
    CTC_API_UNLOCK(lchip);

    return ret;
}

int32
ctc_asw_l2_get_fid_property(uint8 lchip, uint16 fid_id, ctc_l2_fid_property_t property, uint32* value)
{
    uint32 cmd = 0;
    int32  ret = 0;
    IvtProfile_m ivt_profile;
    uint32 ivt_pro_index = 0;
    ivt_pro_index = (fid_id < 128) ? fid_id : 0;

    CTC_PTR_VALID_CHECK(value);
    CTC_ASW_FID_RANGE_CHECK(fid_id);

    CTC_API_LOCK(lchip);
    cmd = DRV_IOR(IvtProfile_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, ivt_pro_index, cmd, &ivt_profile);

    switch (property)
    {
        case CTC_L2_FID_PROP_LEARNING:
            *value = GetIvtProfile(V, fidCfgSa_f, &ivt_profile);
            break;
        case CTC_L2_FID_PROP_DROP_UNKNOWN_UCAST:
            *value = GetIvtProfile(V, ulfDrop_f, &ivt_profile);
            break;
        case CTC_L2_FID_PROP_DROP_UNKNOWN_MCAST:
            *value = GetIvtProfile(V, mlfDrop_f, &ivt_profile);
            break;
        case CTC_L2_FID_PROP_DROP_BCAST:
            *value = GetIvtProfile(V, bcDrop_f, &ivt_profile);
            break;
        default:
           ret = CTC_E_INVALID_PARAM;
           break;
    }
    CTC_API_UNLOCK(lchip);

    return ret;
}

int32
ctc_asw_l2_fdb_init(uint8 lchip,void* l2_fdb_global_cfg)
{
    ArlCtrlReg_m    arc_ctrl;
    McHashCtrl_m    mc_hash_ctrl;
    HashCtrl_m       uc_hash_ctrl;
    AgeTimerCtrl_m  age_timer_ctrl;
    MacLkupCtrl_m        mac_lkup_ctrl;
    PortFastAgingCfg_m  port_fast_aging;
    uint32  cmd = 0;
    int32   ret = 0;
    uint32  i = 0;
    uint32  value = 0;
    ctc_l2_fdb_global_cfg_t * l2_fdb_global = NULL;

    CTC_PTR_VALID_CHECK(l2_fdb_global_cfg);

    l2_fdb_global = l2_fdb_global_cfg;
    sal_memset(&arc_ctrl, 0, sizeof(arc_ctrl));
    sal_memset(&mc_hash_ctrl, 0, sizeof(mc_hash_ctrl));
    sal_memset(&uc_hash_ctrl, 0, sizeof(uc_hash_ctrl));
    sal_memset(&age_timer_ctrl, 0, sizeof(age_timer_ctrl));
    sal_memset(&port_fast_aging, 0, sizeof(port_fast_aging));
    sal_memset(&mac_lkup_ctrl, 0, sizeof(mac_lkup_ctrl));

    cmd = DRV_IOR(ArlCtrlReg_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, i, cmd, &arc_ctrl);
    SetArlCtrlReg(V,moveIntThd_f,&arc_ctrl,1);
    SetArlCtrlReg(V,learnIntThd_f,&arc_ctrl,1);
    SetArlCtrlReg(V,moveIntTimer_f,&arc_ctrl,1);
    SetArlCtrlReg(V,learnIntTimer_f,&arc_ctrl,1);
    SetArlCtrlReg(V,sa0NotLearn_f,&arc_ctrl,1);
    #if 0
    SetArlCtrlReg(V,daUpdateDisable_f,&arc_ctrl,1);
    #endif
    cmd = DRV_IOW(ArlCtrlReg_t,DRV_ENTRY_FLAG);
    ret = ret ? ret :DRV_IOCTL(lchip,0,cmd,&arc_ctrl);
    /* aging init */
    SetAgeTimerCtrl(V,agingRTrip_f,&age_timer_ctrl,5);
    SetAgeTimerCtrl(V,agingEntry_f,&age_timer_ctrl,1);
    cmd = DRV_IOW(AgeTimerCtrl_t,DRV_ENTRY_FLAG);
    ret = ret ? ret : DRV_IOCTL(lchip,0,cmd,&age_timer_ctrl);
    /* hw-learning */
    value = (l2_fdb_global->hw_learn_en) ? 0 : 1;
    for (i = 0; i < CTC_ASW_MAX_PORT_NUM_PER_CHIP; i++)
    {
        cmd = DRV_IOR(MacLkupCtrl_t, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, i, cmd, &mac_lkup_ctrl);
        SetMacLkupCtrl(V,newLearnMode_f,&mac_lkup_ctrl,value);
        /* hw_learning_sync_en */
        SetMacLkupCtrl(V,newsaToFifo_f,&mac_lkup_ctrl,value);
        SetMacLkupCtrl(V,smacFilter_f,&mac_lkup_ctrl,1);
        SetMacLkupCtrl(V,dmacFilter_f,&mac_lkup_ctrl,1);
        cmd = DRV_IOW(MacLkupCtrl_t, DRV_ENTRY_FLAG);
        ret = ret ? ret : DRV_IOCTL(lchip, i, cmd, &mac_lkup_ctrl);
    }
    /* need to flush for state */
    cmd = DRV_IOR(PortFastAgingCfg_t, DRV_ENTRY_FLAG);
    ret = ret ? ret : DRV_IOCTL(lchip,0,cmd,&port_fast_aging);
    SetPortFastAgingCfg(V,enable_f,&port_fast_aging,1);
    SetPortFastAgingCfg(V,glbFastAging_f,&port_fast_aging,1);
    cmd = DRV_IOW(PortFastAgingCfg_t,DRV_ENTRY_FLAG);
    ret = ret ? ret : DRV_IOCTL(lchip,0,cmd,&port_fast_aging);
    SetPortFastAgingCfg(V,enable_f,&port_fast_aging,0);
    cmd = DRV_IOW(PortFastAgingCfg_t,DRV_ENTRY_FLAG);
    ret = ret ? ret : DRV_IOCTL(lchip,0,cmd,&port_fast_aging);
    return ret;
}

int32
ctc_asw_l2_fdb_deinit(uint8 lchip)
{
    return CTC_E_NONE;
}
